package rabbit.flt.core.loader;

import rabbit.flt.common.exception.FltException;
import rabbit.flt.core.PluginClassLoader;

import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 默认类加载器，适用于agent方式启动
 */
public class DefaultPluginClassLoader extends PluginClassLoader {

    private URLClassLoader urlClassLoader = null;

    /**
     * class loader初始化锁
     */
    private ReentrantLock classLoaderLock = new ReentrantLock();

    public DefaultPluginClassLoader() {
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            if (null != urlClassLoader) {
                try {
                    urlClassLoader.close();
                    urlClassLoader = null;
                } catch (IOException e) {
                    throw new FltException(e);
                }
            }
        }));
    }

    /**
     * 通过子类加载器加载插件类
     *
     * @param name
     * @return
     * @throws ClassNotFoundException
     * @throws MalformedURLException
     */
    @Override
    public Class<?> loadClassByName(String name) throws ClassNotFoundException, MalformedURLException, URISyntaxException {
        if (null == urlClassLoader) {
            initClassLoader();
        }
        logger.info("load plugin class[{}]", name);
        return urlClassLoader.loadClass(name);
    }

    /**
     * 初始化classLoader
     */
    private void initClassLoader() throws MalformedURLException, URISyntaxException {
        try {
            classLoaderLock.lock();
            if (null != urlClassLoader) {
                return;
            }
            urlClassLoader = newClassLoader();
        } finally {
            classLoaderLock.unlock();
        }
    }

    private URLClassLoader newClassLoader() throws MalformedURLException, URISyntaxException {
        ClassLoader parent = Thread.currentThread().getContextClassLoader();
        return new URLClassLoader(new URL[]{new File(getAgentJarFilePath()).toURI().toURL()}, parent);
    }
}
